﻿using System.Diagnostics;

namespace DimensionsHelper.LanguageService.Syntax;

public class ForStatement : BodiedStatement
{
    private Identifier _counterIdentifier;
    private SyntaxToken _equalToken;
    private RangeExpression _rangeExpression;
    private SyntaxToken _nextKeywordToken;
    private IntegerLiteral? _stepInteger;
    private SyntaxToken? _stepKeywordToken;

    internal ForStatement(SyntaxToken forKeywordToken, SyntaxNode? parent) :
        base(SyntaxKinds.ForStatement, parent)
    {
        ForKeywordToken = forKeywordToken;
        _counterIdentifier = Identifier.Default;
        _equalToken = SyntaxToken.Default;
        _rangeExpression = RangeExpression.Empty;
        _nextKeywordToken = SyntaxToken.Default;
    }


    public SyntaxToken ForKeywordToken { get; }
    
    public SyntaxToken NextKeywordToken => _nextKeywordToken;

    public Identifier CounterIdentifier => _counterIdentifier;

    public SyntaxToken EqualToken => _equalToken;
    
    public RangeExpression RangeExpression => _rangeExpression;
    
    public SyntaxToken? StepKeywordToken => _stepKeywordToken;

    public IntegerLiteral? StepInteger => _stepInteger;


    public void Update(Identifier counter, SyntaxToken equalToken, RangeExpression range)
    {
        Debug.Assert(equalToken == SyntaxToken.Default || equalToken.IsNode(SyntaxKinds.EqualToken));
        Debug.Assert(range != RangeExpression.Empty);
        SetChildField(ref _counterIdentifier, Identifier.IsDefaultOrEmpty, counter);
        SetChildField(ref _equalToken, SyntaxToken.IsNullOrEmpty, equalToken);
        SetChildField(ref _rangeExpression, RangeExpression.IsEmptyRange, range);
    }


    public void Update(SyntaxToken stepKeywordToken, IntegerLiteral stepInteger)
    {
        Debug.Assert(stepKeywordToken == SyntaxToken.Default ||
                     stepKeywordToken.IsNode(SyntaxKinds.StepKeywordToken));
        SetChildNullableField(ref _stepKeywordToken, stepKeywordToken);
        SetChildNullableField(ref _stepInteger, stepInteger);
    }


    public void Update(SyntaxToken nextKeywordToken)
    {
        Debug.Assert(nextKeywordToken.IsNode(SyntaxKinds.NextKeywordToken));
        SetChildField(ref _nextKeywordToken, SyntaxToken.IsNullOrEmpty, nextKeywordToken);
    }


    public override void AcceptVisitor<T>(SyntaxNodeVisitor<T> visitor)
    {
        Accept(visitor, ForKeywordToken, CounterIdentifier, EqualToken,
            RangeExpression, StepKeywordToken, StepInteger, Body, NextKeywordToken);
    }
}


public static partial class NodeFactory
{
    public static ForStatement CreateForStatement(SyntaxNode? parent, SyntaxToken forKeywordToken)
    {
        Debug.Assert(forKeywordToken.IsNode(SyntaxKinds.ForKeywordToken));
        return new ForStatement(forKeywordToken, parent);
    }
}